# -*- coding: utf-8 -*-
# @Author : 赵陈
# @Date   : 2019/10/9
# @File   : R41_TX_EntAnnualIncomeTaxAmtCheck_new.py.py
# @E-mail : zhaochen@bbdservice.com


'''eof
name:企业纳税年均纳税额校验（同时有A1表和年度汇算清缴表）
code:R41_TX_EntAnnualIncomeTaxAmtCheck
tableName:
columnName:
groups:场景业务校验-税务
dependencies:TX_CQ_DSJ
type:常用指标
datasourceType:在线指标
description:
eof'''

import json
import re
import sys
import time,datetime
import pandas as pd
import math
from dateutil import rrule
from dateutil.relativedelta import relativedelta

reload(sys)
sys.setdefaultencoding('utf-8')



def formatData(table_Name):
    """
    获取数据
    :param table_Name:字典keys
    :return:[{}]
    """
    try:
        data = TX_CQ_DSJ["data"].get(table_Name)
        return data if isinstance(data, list) and len(data) > 0 else [{}]

    except:
        return [{}]

def dataPre(dataList=None, key=None):
    """
    对list里面的列表去重月份不标准的
    :param dataList:
    :param key:
    :return:
    """
    dataListTemp = dataList
    data = []
    for i in range(len(dataListTemp)):
        temp = dataListTemp[i].get(key)
        try:
            temp = int(temp)
        except:
            temp = None
            pass

        if temp:
            data.append(dataListTemp[i])
        else:
            pass

    if len(data) == 0:
        data = [{}]
    else:
        pass

    return data

def convertDataType(data_value, data_type):
    """
    数据格式转换
    :param data_value:
    :param data_type: float/int/str/date_time
    :return:
    """
    data_value = str(data_value)
    return_data = None
    # float
    if data_type == 'float':
        try:
            return_data = float(data_value) if len(data_value) >= 0 else None
        except:
            return_data = None
    # int
    elif data_type == 'int':
        try:
            return_data = int(data_value) if len(data_value) >= 0 else None
        except:
            return_data = None
    # str
    elif data_type == 'str':
        try:
            return_data = str(data_value) if len(data_value) >= 0 else None
        except:
            return_data = None
    # date_time
    elif data_type == 'date_time':
        r = re.compile(r'\D+')
        try:
            return_data = datetime.datetime.strptime(data_value, '%Y.%m.%d').strftime('%Y-%m-%d')
        except:
            try:
                return_data = datetime.datetime.strptime(data_value, '%Y-%m-%d').strftime('%Y-%m-%d')
            except:
                try:
                    return_data = datetime.datetime.strptime(data_value, '%Y/%m/%d').strftime('%Y-%m-%d')
                except:
                    try:
                        data_value = r.sub('', data_value)
                        return_data = datetime.datetime.strptime(data_value, '%Y%m%d').strftime('%Y-%m-%d')
                    except:
                        return_data = None

    return return_data



def count_qz(data,time1,time2,time3,index,list):
    if data != [{}]:
        data = sorted(data, key=lambda x: int(x[time3]))
        for i in range(len(data)):

            try:
                ND_q = int(data[i][time1][0:4])
                ND_z = int(data[i][time2][0:4])
                YF_q = int(data[i][time1][5:7])
                YF_z = int(data[i][time2][5:7])

                if ND_q == ND_z and YF_q == YF_z:
                    if ND_z and YF_z:
                        NDYF = str(ND_z) + str(YF_z)
                        if NDYF in list.index:
                            tax_amount = convertDataType(data[i].get(index), 'float')
                            if tax_amount is not None:
                                if math.isnan(list.loc[str(ND_z) + str(YF_z)]):
                                    list.loc[str(ND_z) + str(YF_z)] = tax_amount
                                else:
                                    pass
                elif ND_q != ND_z or YF_q != YF_z:
                    time_q = datetime.datetime(ND_q, YF_q, 1)
                    time_z = datetime.datetime(ND_z, YF_z, 1)
                    time_gap = rrule.rrule(rrule.MONTHLY, dtstart=time_q, until=time_z).count()
                    for j in range(time_gap):
                        # print(j)
                        change_time = time_z - relativedelta(months=+j)
                        # print(change_time)
                        ND = int(change_time.year)
                        YF = int(change_time.month)
                        if ND and YF:
                            NDYF = str(ND) + str(YF)
                            if NDYF in list.index:
                                tax_amount = convertDataType(data[i].get(index), 'float')
                                if tax_amount is not None:
                                    if math.isnan(list.loc[str(ND) + str(YF)]):
                                        list.loc[str(ND) + str(YF)] = tax_amount / time_gap
                                    else:

                                        pass
                else:
                    pass
            except:


                pass
    else:
        pass
    return list

def vatDataMerge(syptZzsxgm, syptZzsybnsr,syptSwdjxx,putBackYear=2, CcrDate=None):
    """
    增值税纳税数据拆分为近两年的月度数据

    :param syptZzsxgm:小规模增值税纳税表[{}]；
    :param syptZzsybnsr:一般纳税人增值税表[{}]；
    :param putBackYear:回推时间，默认为2年；
    :param CcrDate:测试时间，默认为None，格式为datetime.date(2019, 2, 19)；
    :return: VatData为Series
    """
    # 字典排序
    syptZzsxgm = dataPre(syptZzsxgm, key='YF')
    syptZzsybnsr = dataPre(syptZzsybnsr, key='YF')
    NSRZG_DM=syptSwdjxx[0].get('NSRZG_DM')


    # 生成时间轴
    dateIndexList = []
    if CcrDate is None:
        CcrYearMonth = datetime.datetime.now().strftime('%Y-%m-%d')[:7]
        CcrDate = CcrYearMonth + '-01'
        StartDateTmp = str(datetime.datetime.now().year - putBackYear) + CcrDate[4:]
        StartDate = StartDateTmp[:7] + '-01'
    else:
        CcrYear = datetime.datetime.strptime(convertDataType(CcrDate, 'date_time'), '%Y-%m-%d').date().year
        CcrDate = convertDataType(CcrDate, 'date_time')[:7] + '-01'
        StartDate = str(CcrYear - putBackYear) + convertDataType(CcrDate, 'date_time')[4:]

    dateSet = pd.date_range(StartDate, CcrDate, freq='M')

    for i in dateSet:
        year = i.date().year
        month = i.date().month
        dateIndexList.append(str(year) + str(month))

    VatData = pd.Series(None, index=dateIndexList)

    if syptZzsxgm == [{}] and syptZzsybnsr == [{}]:
        return VatData
    else:
        # 小规模
        if NSRZG_DM==u'204'  or  NSRZG_DM==u'205':
            NSRZG='xgm'
        # 一般纳税人
        else:
            NSRZG = 'yb'
        if NSRZG == 'yb':
            VatData=count_qz(data=syptZzsybnsr, time1='skssqq', time2='skssqz', time3='YF', index='YNSEHJ', list=VatData)
            # print(VatData)
            VatData = count_qz(data=syptZzsxgm,time1='skssqq',time2='skssqz',time3='YF',index='YNSEHJDBNBQ',list=VatData)

        else:
            VatData = count_qz(data=syptZzsxgm, time1='skssqq', time2='skssqz', time3='YF', index='YNSEHJDBNBQ',
                               list=VatData)

            VatData = count_qz(data=syptZzsybnsr, time1='skssqq', time2='skssqz', time3='YF', index='YNSEHJ',
                               list=VatData)
    return VatData


def incomeTaxDataMerge(syptQysdsNd, syptQysdsA1, putBackYear=2, CcrDate=None):
    """
    所得税纳税数据拆分为近2年的月度数据

    :param syptQysdsNd: 年度汇算清缴表，类型[{}]
    :param syptQysdsA1: A1表，类型[{}]
    :param putBackYear: 回推时间，默认为2年
    :param CcrDate: 测试时间，默认为None；
    :return: IncomeTaxData为Series
    """
    # 字典排序
    syptQysdsNd = dataPre(syptQysdsNd, key='ND')
    syptQysdsA1 = dataPre(syptQysdsA1, 'YF')


    # 生成时间轴
    dateIndexList = []
    # 用于生产
    if CcrDate is None:
        CcrYearMonth = datetime.datetime.now().strftime('%Y-%m-%d')[:7]
        CcrDate = CcrYearMonth + '-01'
        StartDateTmp = str(datetime.datetime.now().year - putBackYear) + CcrDate[4:]
        StartDate = StartDateTmp[:7] + '-01'
    else:
        CcrYear = datetime.datetime.strptime(convertDataType(CcrDate, 'date_time'), '%Y-%m-%d').date().year
        CcrDate = convertDataType(CcrDate, 'date_time')[:7] + '-01'
        StartDate = str(CcrYear - putBackYear) + convertDataType(CcrDate, 'date_time')[4:]

    dateSet = pd.date_range(StartDate, CcrDate, freq='M')
    for i in dateSet:
        year = i.date().year
        month = i.date().month
        dateIndexList.append(str(year) + str(month))

    IncomeTaxData = pd.Series(None, index=dateIndexList)

    if syptQysdsNd == [{}] and syptQysdsA1 == [{}]:
        return IncomeTaxData
    else:
         # 使用年度汇算清缴表
        IncomeTaxData = count_qz(data=syptQysdsNd, time1='skssqq', time2='skssqz', time3='ND', index='YNSDSE', list=IncomeTaxData)

        # 使用A1表(默认为只有按季度缴
        IncomeTaxData = count_qz(data=syptQysdsA1, time1='skssqq', time2='skssqz', time3='YF', index='YNSSDE',
                                 list=IncomeTaxData)


        return IncomeTaxData

def incomePriorityCondition_yb(syptZzsybnsr,income_list):
    """
    优先判断条件：计算近两年销售收入， 优先取一般纳税人
    :param syptZzsxgm: 小规模
    :param syptZzsybnsr: 一般纳税人
    :param putBackYear:
    :param CcrDate:
    :return:
    """
    # 字典排序
    # syptZzsybnsr = dataPre(syptZzsybnsr, key='YF')

    if syptZzsybnsr == [{}]:
        return income_list
    else:
        # 一般纳税人
        syptZzsybnsr = sorted(syptZzsybnsr, key=lambda x: int(x['YF']))
        for i in range(len(syptZzsybnsr)):
            ND_q = int(syptZzsybnsr[i]['skssqq'][0:4])
            ND_z = int(syptZzsybnsr[i]['skssqz'][0:4])
            YF_q = int(syptZzsybnsr[i]['skssqq'][5:7])
            YF_z = int(syptZzsybnsr[i]['skssqz'][5:7])
            if ND_q == ND_z and YF_q == YF_z:
                if ND_z and YF_z:
                    NDYF = str(ND_z) + str(YF_z)
                    if NDYF in income_list.index:
                        ASYSLJSDNSJCYBJSE = convertDataType(syptZzsybnsr[i].get('ASYSLJSDNSJCYBJSE'), 'float')
                        AJYZSBFZSHWXSE = convertDataType(syptZzsybnsr[i].get('AJYZSBFZSHWXSE'), 'float')
                        MDTBFCKHWXSE = convertDataType(syptZzsybnsr[i].get('MDTBFCKHWXSE'), 'float')
                        MSHWJLWXSE = convertDataType(syptZzsybnsr[i].get('MSHWJLWXSE'), 'float')
                        if ASYSLJSDNSJCYBJSE is None and AJYZSBFZSHWXSE is None and MDTBFCKHWXSE is None \
                            and MSHWJLWXSE is None:
                            income = None
                        else:
                            ASYSLJSDNSJCYBJSE = ASYSLJSDNSJCYBJSE if ASYSLJSDNSJCYBJSE is not None else 0
                            AJYZSBFZSHWXSE = AJYZSBFZSHWXSE if AJYZSBFZSHWXSE is not None else 0
                            MDTBFCKHWXSE = MDTBFCKHWXSE if MDTBFCKHWXSE is not None else 0
                            MSHWJLWXSE = MSHWJLWXSE if MSHWJLWXSE is not None else 0

                            income = ASYSLJSDNSJCYBJSE + AJYZSBFZSHWXSE + MDTBFCKHWXSE + MSHWJLWXSE

                        if income is not None:
                            if math.isnan(income_list.loc[NDYF]):
                                income_list.loc[NDYF] = income
                    else:
                        pass
                else:
                    pass
            elif ND_q != ND_z or YF_q != YF_z:
                time_q = datetime.datetime(ND_q, YF_q, 1)
                time_z = datetime.datetime(ND_z, YF_z, 1)
                time_gap = rrule.rrule(rrule.MONTHLY, dtstart=time_q, until=time_z).count()
                for j in range(time_gap):
                    # print(j)
                    change_time = time_z - relativedelta(months=+j)
                    # print(change_time)
                    ND = int(change_time.year)
                    YF = int(change_time.month)
                    if ND and YF:
                        NDYF = str(ND) + str(YF)
                        if NDYF in income_list.index:
                            ASYSLJSDNSJCYBJSE = convertDataType(syptZzsybnsr[i].get('ASYSLJSDNSJCYBJSE'), 'float')
                            AJYZSBFZSHWXSE = convertDataType(syptZzsybnsr[i].get('AJYZSBFZSHWXSE'), 'float')
                            MDTBFCKHWXSE = convertDataType(syptZzsybnsr[i].get('MDTBFCKHWXSE'), 'float')
                            MSHWJLWXSE = convertDataType(syptZzsybnsr[i].get('MSHWJLWXSE'), 'float')

                            if ASYSLJSDNSJCYBJSE is None and AJYZSBFZSHWXSE is None and MDTBFCKHWXSE is None \
                                and MSHWJLWXSE is None:
                                income = None
                            else:
                                ASYSLJSDNSJCYBJSE = ASYSLJSDNSJCYBJSE if ASYSLJSDNSJCYBJSE is not None else 0
                                AJYZSBFZSHWXSE = AJYZSBFZSHWXSE if AJYZSBFZSHWXSE is not None else 0
                                MDTBFCKHWXSE = MDTBFCKHWXSE if MDTBFCKHWXSE is not None else 0
                                MSHWJLWXSE = MSHWJLWXSE if MSHWJLWXSE is not None else 0

                                income = ASYSLJSDNSJCYBJSE + AJYZSBFZSHWXSE + MDTBFCKHWXSE + MSHWJLWXSE
                            if income is not None:
                                if math.isnan(income_list.loc[str(ND) + str(YF)]):
                                    income_list.loc[str(ND) + str(YF)] = income / time_gap
                                else:
                                    pass
                            else:
                                pass
                        else:
                            pass
                    else:
                        pass
            else:
                pass

    return income_list

def incomePriorityCondition_xgm(syptZzsxgm, income_list):
    """
    优先判断条件：计算近两年销售收入， 优先取一般纳税人
    :param syptZzsxgm: 小规模
    :param syptZzsybnsr: 一般纳税人
    :param putBackYear:
    :param CcrDate:
    :return:
    """
    # 字典排序
    # syptZzsxgm = dataPre(syptZzsxgm, key='YF')

    if syptZzsxgm == [{}]:
        return income_list
    else:
        # 小规模
        syptZzsxgm = sorted(syptZzsxgm, key=lambda x: int(x['YF']))
        for i in range(len(syptZzsxgm)):
            ND_q = int(syptZzsxgm[i]['skssqq'][0:4])
            ND_z = int(syptZzsxgm[i]['skssqz'][0:4])
            YF_q = int(syptZzsxgm[i]['skssqq'][5:7])
            YF_z = int(syptZzsxgm[i]['skssqz'][5:7])
            if ND_q == ND_z and YF_q == YF_z:
                if ND_z and YF_z:
                    NDYF = str(ND_z) + str(YF_z)
                    if NDYF in income_list.index:
                        YZZZSHWJLWBHSXSEBNBQ = convertDataType(syptZzsxgm[i].get('YZZZSHWJLWBHSXSEBNBQ'), 'float')
                        XSCZBDCBHSXSE = convertDataType(syptZzsxgm[i].get('XSCZBDCBHSXSE'), 'float')
                        MSHWJLWXSEBNBQ = convertDataType(syptZzsxgm[i].get('MSHWJLWXSEBNBQ'), 'float')
                        CKMSHWXSEBNBQ = convertDataType(syptZzsxgm[i].get('CKMSHWXSEBNBQ'), 'float')
                        if YZZZSHWJLWBHSXSEBNBQ is None and XSCZBDCBHSXSE is None and MSHWJLWXSEBNBQ is None \
                            and CKMSHWXSEBNBQ is None:
                            income = None
                        else:
                            YZZZSHWJLWBHSXSEBNBQ = YZZZSHWJLWBHSXSEBNBQ if YZZZSHWJLWBHSXSEBNBQ is not None else 0
                            XSCZBDCBHSXSE = XSCZBDCBHSXSE if XSCZBDCBHSXSE is not None else 0
                            MSHWJLWXSEBNBQ = MSHWJLWXSEBNBQ if MSHWJLWXSEBNBQ is not None else 0
                            CKMSHWXSEBNBQ = CKMSHWXSEBNBQ if CKMSHWXSEBNBQ is not None else 0

                            income = YZZZSHWJLWBHSXSEBNBQ + XSCZBDCBHSXSE + MSHWJLWXSEBNBQ + CKMSHWXSEBNBQ
                        if income is not None:
                            if math.isnan(income_list.loc[NDYF]):
                                income_list.loc[NDYF] = income
                    else:
                        pass
                else:
                    pass
            elif ND_q != ND_z or YF_q != YF_z:
                time_q = datetime.datetime(ND_q, YF_q, 1)
                time_z = datetime.datetime(ND_z, YF_z, 1)
                time_gap = rrule.rrule(rrule.MONTHLY, dtstart=time_q, until=time_z).count()
                for j in range(time_gap):
                    # print(j)
                    change_time = time_z - relativedelta(months=+j)
                    # print(change_time)
                    ND = int(change_time.year)
                    YF = int(change_time.month)
                    if ND and YF:
                        NDYF = str(ND) + str(YF)
                        if NDYF in income_list.index:
                            YZZZSHWJLWBHSXSEBNBQ = convertDataType(syptZzsxgm[i].get('YZZZSHWJLWBHSXSEBNBQ'), 'float')
                            XSCZBDCBHSXSE = convertDataType(syptZzsxgm[i].get('XSCZBDCBHSXSE'), 'float')
                            MSHWJLWXSEBNBQ = convertDataType(syptZzsxgm[i].get('MSHWJLWXSEBNBQ'), 'float')
                            CKMSHWXSEBNBQ = convertDataType(syptZzsxgm[i].get('CKMSHWXSEBNBQ'), 'float')

                            if YZZZSHWJLWBHSXSEBNBQ is None and XSCZBDCBHSXSE is None and MSHWJLWXSEBNBQ is None \
                                and CKMSHWXSEBNBQ is None:
                                income = None
                            else:
                                YZZZSHWJLWBHSXSEBNBQ = YZZZSHWJLWBHSXSEBNBQ if YZZZSHWJLWBHSXSEBNBQ is not None else 0
                                XSCZBDCBHSXSE = XSCZBDCBHSXSE if XSCZBDCBHSXSE is not None else 0
                                MSHWJLWXSEBNBQ = MSHWJLWXSEBNBQ if MSHWJLWXSEBNBQ is not None else 0
                                CKMSHWXSEBNBQ = CKMSHWXSEBNBQ if CKMSHWXSEBNBQ is not None else 0

                                income = YZZZSHWJLWBHSXSEBNBQ + XSCZBDCBHSXSE + MSHWJLWXSEBNBQ + CKMSHWXSEBNBQ
                            if income is not None:
                                if math.isnan(income_list.loc[str(ND) + str(YF)]):
                                    income_list.loc[str(ND) + str(YF)] = income / time_gap
                                else:

                                    pass
                            else:
                                pass
                        else:
                            pass
                    else:
                        pass
            else:
                pass

    return income_list

def incomePriorityCondition(syptZzsxgm, syptZzsybnsr,syptSwdjxx, putBackYear=2, CcrDate=None):
    """
    优先判断条件：计算近两年销售收入， 优先取一般纳税人
    :param syptZzsxgm: 小规模
    :param syptZzsybnsr: 一般纳税人
    :param putBackYear:
    :param CcrDate:
    :return:
    """
    # 字典排序
    syptZzsxgm = dataPre(syptZzsxgm, key='YF')
    syptZzsybnsr = dataPre(syptZzsybnsr, key='YF')
    NSRZG_DM=syptSwdjxx[0].get('NSRZG_DM')

    # 生成时间轴
    dateIndexList = []
    if CcrDate is None:
        CcrYearMonth = datetime.datetime.now().strftime('%Y-%m-%d')[:7]
        CcrDate = CcrYearMonth + '-01'
        StartDateTmp = str(datetime.datetime.now().year - putBackYear) + CcrDate[4:]
        StartDate = StartDateTmp[:7] + '-01'
    else:
        CcrYear = datetime.datetime.strptime(convertDataType(CcrDate, 'date_time'), '%Y-%m-%d').date().year
        CcrDate = convertDataType(CcrDate, 'date_time')[:7] + '-01'
        StartDate = str(CcrYear - putBackYear) + convertDataType(CcrDate, 'date_time')[4:]

    dateSet = pd.date_range(StartDate, CcrDate, freq='M')

    for i in dateSet:
        year = i.date().year
        month = i.date().month
        dateIndexList.append(str(year) + str(month))
    # 用于保存 按月求和的销售收入
    income_list = pd.Series(None, index=dateIndexList)

    if syptZzsxgm == [{}] and syptZzsybnsr == [{}]:
        return income_list
    else:
        # 小规模
        if NSRZG_DM==u'204'  or  NSRZG_DM==u'205':
            NSRZG='xgm'
        # 一般纳税人
        else:
            NSRZG = 'yb'
        if NSRZG == 'yb':
            income_list=incomePriorityCondition_yb(syptZzsybnsr, income_list)

            income_list = incomePriorityCondition_xgm(syptZzsxgm,income_list)

        else:
            income_list = incomePriorityCondition_xgm(syptZzsxgm,income_list)

            income_list=incomePriorityCondition_yb(syptZzsybnsr, income_list)

    return income_list


def entAnnualTaxAmtCheck(spDate=None):
    """
    企业年均纳税额校验（同时有A1表和年度汇算清缴表）
    :return:
    """
    syptQysdsNd = formatData('syptQysdsNd')
    syptQysdsA1 = formatData('syptQysdsA1')
    syptZzsxgm = formatData('syptZzsxgm')
    syptZzsybnsr = formatData('syptZzsybnsr')
    syptSwdjxx = formatData('syptSwdjxx')
    # 所得税数据合并
    if syptQysdsA1 == [{}] and syptQysdsNd == [{}]:
        return -0.001
    else:

        incomeTaxDataSeries = incomeTaxDataMerge(syptQysdsNd=syptQysdsNd, syptQysdsA1=syptQysdsA1, CcrDate=spDate)
        incomeTaxDataSeries = incomeTaxDataSeries.fillna(value=0)

        lastOneIncomeTaxSum = sum(incomeTaxDataSeries[-12:])
        lastTwoIncomeTaxSum = sum(incomeTaxDataSeries[:12])

        if syptZzsxgm == [{}] and syptZzsybnsr == [{}]:
            f = lastOneIncomeTaxSum * 0.65 + lastTwoIncomeTaxSum * 0.35
            return round(f, 4)
        else:
            incomeDataSeries = incomePriorityCondition(syptZzsxgm=syptZzsxgm, syptZzsybnsr=syptZzsybnsr,syptSwdjxx=syptSwdjxx,CcrDate=spDate)
            incomeDataSeries = incomeDataSeries.fillna(value=0)
            incomeOneSum = sum(incomeDataSeries[-12:]) # 最近1年
            incomeTwoSum = sum(incomeDataSeries[:12]) # 最近第2年

            if incomeTwoSum == 0:
                f = lastOneIncomeTaxSum * 0.65 + lastTwoIncomeTaxSum * 0.35
                return round(f, 4)

            factor3 = (incomeOneSum - incomeTwoSum) / incomeTwoSum
            if factor3 > -0.5:
                f = lastOneIncomeTaxSum * 0.65 + lastTwoIncomeTaxSum * 0.35
                return round(f, 4)
            else:
                if factor3 > -0.7 and factor3 <= -0.5:
                    return round(lastOneIncomeTaxSum, 4)
                if factor3 <= -0.7:
                    if incomeOneSum < 2000000:
                        return 0
                    else:
                        return round(lastOneIncomeTaxSum, 4)




result = entAnnualTaxAmtCheck()

if __name__ == "__main__":
    file_obj = open('G:\\data.json', 'r')
    content = file_obj.read()
    TX_CQ_DSJ = json.loads(content, strict=False)
    aa = entAnnualTaxAmtCheck()
    print aa